package com.momo.service.sysSetting;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.momo.common.common.JSONResult;
import com.momo.common.error.RedisKeyEnum;
import com.momo.common.req.sysSetting.group.UserGroupReq;
import com.momo.common.req.sysSetting.authority.BatchRoleUserReq;
import com.momo.common.req.sysSetting.authority.RoleReq;
import com.momo.common.req.sysmain.RedisUser;
import com.momo.common.res.authority.AclModuleLevelDto;
import com.momo.common.res.authority.AllRolesRes;
import com.momo.common.res.authority.LoginAuthReq;
import com.momo.common.util.DateUtil;
import com.momo.common.util.RedisUtil;
import com.momo.common.util.StrUtil;
import com.momo.mapper.dataobject.*;
import com.momo.mapper.mapper.sysSetting.AuthorityMapper;
import com.momo.mapper.mapper.sysSetting.RoleMapper;
import com.momo.mapper.mapper.sysSetting.VipMapper;
import com.momo.mapper.mapper.sysmain.SysUserMapper;
import com.momo.service.async.AclAsync;
import com.momo.service.authority.AdminAuthorityService;
import com.momo.service.authority.CommonAuthorityService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * Created by MOMO on 2019/3/22.
 */
@Service
@Slf4j
public class SysRoleServiceImpl implements SysRoleService {
    @Autowired
    private RoleMapper roleMapper;
    @Autowired
    private SysUserMapper sysUserMapper;
    @Autowired
    private AuthorityMapper authorityMapper;
    @Autowired
    private AdminAuthorityService adminAuthorityService;
    @Autowired
    private CommonAuthorityService commonAuthorityService;
    @Autowired
    private AclAsync aclAsync;
    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private VipMapper vipMapper;

    @Override
    public JSONResult add(RoleReq roleReq, RedisUser redisUser) {
        int roleCount = roleMapper.checkRoleRepetition(roleReq.getSysRoleName(), roleReq.getGroupId(), null);
        if (roleCount > 0) {
            return JSONResult.errorMap("角色名称已存在");
        }
        RoleDO record = new RoleDO();
        BeanUtils.copyProperties(roleReq, record);
        record.setGroupId(redisUser.getGroupId());
        //第三方的管理员只允许有一个
        if (!redisUser.getGroupId().equals(1L)) {
            //角色的类型，0：管理员角色，1：普通用户 2其他
            if ("0".equals(roleReq.getSysRoleType())) {
                if (checkAdminVipOne(record)) {
                    return JSONResult.errorMap("管理员角色已存在");
                }
            }
        }
        record.setCreateBy(redisUser.getSysUserName());
        record.setUpdateBy(redisUser.getSysUserName());
        record.setCreateTime(DateUtil.getDateTime());
        record.setUpdateTime(DateUtil.getDateTime());
        record.setSysRoleUuid(StrUtil.genUUID());
        roleMapper.insertSelective(record);
        aclAsync.roleToRedis(record);
        return JSONResult.ok("新增角色成功");
    }

    @Override
    public JSONResult modify(RoleReq roleReq, RedisUser redisUser) {
        RoleDO roleDO = roleMapper.uuid(roleReq.getSysRoleUuid());
        if (null == roleDO) {
            return JSONResult.errorMap("待编辑的角色不存在");
        }
        //非总部，不可以操作管理员敏感权限
        if (!redisUser.getGroupId().equals(1L)) {
            //角色的类型，0：管理员角色，1：普通用户 2其他
            //屏蔽非总部操作第三方管理员角色
            if (("0".equals(roleDO.getSysRoleType()) && "1".equals(roleReq.getSysRoleType()))) {
                return JSONResult.errorMap("您无权限操作管理员角色类型");
            }
            //屏蔽非总部操作第三方管理员角色状态
            //状态 0启用  1禁用
            if (("0".equals(roleDO.getSysRoleStatus()) && "1".equals(roleReq.getSysRoleStatus()))) {
                return JSONResult.errorMap("您无权限操作管理员角色状态");
            }
        } else {
           //联系管理员开放操作权限
        }
        int roleCount = roleMapper.checkRoleRepetition(roleReq.getSysRoleName(), roleReq.getGroupId(), roleDO.getId());
        if (roleCount > 0) {
            return JSONResult.errorMap("角色名称已存在");
        }
        RoleDO aDo = new RoleDO();
        BeanUtils.copyProperties(roleReq, aDo);
        aDo.setId(roleDO.getId());
        //第三方的管理员只允许有一个
        if (!roleDO.getGroupId().equals(1L)) {
            //角色的类型，0：管理员角色，1：普通用户 2其他
            if ("0".equals(roleReq.getSysRoleType())) {
                if (checkAdminVipOne(aDo)) {
                    return JSONResult.errorMap("管理员角色已存在");
                }
            }
        }
        aDo.setUpdateBy(redisUser.getSysUserName());
        aDo.setUpdateTime(DateUtil.getDateTime());
        roleMapper.updateByPrimaryKeySelective(aDo);
        aclAsync.roleToRedis(aDo);
        return JSONResult.ok("更新角色成功");
    }

    @Override
    public JSONResult status(RoleReq roleReq, RedisUser redisUser) {
        RoleDO roleDO = roleMapper.uuid(roleReq.getSysRoleUuid());
        if (null == roleDO) {
            return JSONResult.errorMap("待编辑的角色不存在");
        }
        //非总部，不可以操作管理员敏感权限
        if (!redisUser.getGroupId().equals(1L) && "0".equals(roleDO.getSysRoleType())) {
            return JSONResult.errorMap("您无权限操作");
        }
        String statusMsg = "";
        //状态 0启用  1禁用
        if ("0".equals(roleReq.getSysRoleStatus())) {
            roleDO.setSysRoleStatus("1");
            statusMsg = "角色状态 禁用 成功";
        } else if ("1".equals(roleReq.getSysRoleStatus())) {
            roleDO.setSysRoleStatus("0");
            statusMsg = "角色状态 启用 成功";
        }
        roleDO.setUpdateBy(redisUser.getSysUserName());
        roleDO.setUpdateTime(DateUtil.getDateTime());
        roleMapper.updateByPrimaryKeySelective(roleDO);
        aclAsync.roleToRedis(roleDO);
        return JSONResult.ok(statusMsg);
    }

    @Override
    public JSONResult detail(RoleReq roleReq, RedisUser redisUser) {
        RoleDO roleDO = roleMapper.uuid(roleReq.getSysRoleUuid());
        if (null == roleDO) {
            return JSONResult.errorMap("待查询的角色不存在");
        }
        return JSONResult.ok(roleDO);
    }

    @Override
    public JSONResult rolePage(RoleReq roleReq, RedisUser redisUser) {
        RoleDO roleDO = new RoleDO();
        BeanUtils.copyProperties(roleReq, roleDO);
        roleDO.setGroupId(redisUser.getGroupId());
        PageHelper.startPage(roleReq.getPageNum(), roleReq.getPageSize(), "id desc");
        List<RoleDO> list = roleMapper.rolePage(roleDO);
        PageInfo<RoleDO> pageInfo = new PageInfo<>(list);
        //以下采用硬编码方式
        if (redisUser.getGroupId().equals(1L)) {//总部登录
            //超级管理员登录
            if (redisUser.getId().equals(1L)) {
                return JSONResult.ok(pageInfo);
            } else {
                //非超级管理员登录，剔除掉超级管理员信息
                List<RoleDO> userDOList = pageInfo.getList();
                PageInfo<RoleDO> finalPageInfo = pageInfo(userDOList, pageInfo, redisUser.getAdminRoleId());
                return JSONResult.ok(finalPageInfo);
            }
        } else {//企业登录/第三方登录
            if (redisUser.isAdminRole()) {//如果是管理员
                return JSONResult.ok(pageInfo);
            } else {
                //非管理员登录，剔除掉管理员信息
                List<RoleDO> userDOList = pageInfo.getList();
                PageInfo<RoleDO> finalPageInfo = pageInfo(userDOList, pageInfo, redisUser.getAdminRoleId());
                return JSONResult.ok(finalPageInfo);
            }
        }
    }
    private PageInfo<RoleDO> pageInfo(List<RoleDO> userDOList, PageInfo<RoleDO> pageInfo, Long userId) {
        List<RoleDO> finalUserList = Lists.newArrayList();
        //此处采用硬编码方式，非超级管理员登录，剔除掉超级管理员信息
        userDOList.forEach(userDO1 -> {
            if (!userDO1.getId().equals(userId)) {
                finalUserList.add(userDO1);
            }
        });
        PageInfo<RoleDO> finalPageInfo = new PageInfo<>(finalUserList);
        finalPageInfo.setTotal(pageInfo.getTotal());
        finalPageInfo.setPageNum(pageInfo.getPageNum());
        finalPageInfo.setPageSize(pageInfo.getPageSize());
        return finalPageInfo;
    }

    @Override
    public JSONResult rolesToUser(BatchRoleUserReq batchRoleUserReq, RedisUser redisUser) {
        UserDO userDO = sysUserMapper.uuid(batchRoleUserReq.getUserUuid());
        if (null == userDO) {
            return JSONResult.errorMap("待授权的用户不存在");
        }
        List<Long> roles = batchRoleUserReq.getRoles();
        List<Long> originAclIdList = authorityMapper.rolesByUserId(userDO.getId());
        if (originAclIdList.size() == roles.size()) {
            Set<Long> originAclIdSet = Sets.newHashSet(originAclIdList);
            Set<Long> aclIdSet = Sets.newHashSet(roles);
            originAclIdSet.removeAll(aclIdSet);
            if (CollectionUtils.isEmpty(originAclIdSet)) {
                return JSONResult.ok("为用户授权角色成功");
            }
        }
        updateUserRoles(userDO.getId(), roles, redisUser, userDO.getGroupId());
        return JSONResult.ok("为用户授权角色成功");
    }

    @Override
    public JSONResult aclsToRole(BatchRoleUserReq batchRoleUserReq, RedisUser redisUser) {
        RoleDO roleDO = roleMapper.uuid(batchRoleUserReq.getSysRoleUuid());
        if (null == roleDO) {
            return JSONResult.errorMap("待授权的角色不存在");
        }
        //屏蔽非总部操作第三方管理员角色
        if (!redisUser.getGroupId().equals(1L) && "0".equals(roleDO.getSysRoleType())) {
            return JSONResult.errorMap("您无权限操作");
        }
        List<RoleAclDO> roleAclDOS = batchRoleUserReq.getAcls();
        List<Long> acls = Lists.newArrayList();
        if (!CollectionUtils.isEmpty(roleAclDOS)) {
            roleAclDOS.forEach(roleAclDO -> {
                acls.add(roleAclDO.getSysAclId());
            });
        }
        List<Long> originAclIdList = authorityMapper.aclsByRoleId(Arrays.asList(roleDO.getId()), null);
        if (originAclIdList.size() == acls.size()) {
            Set<Long> originAclIdSet = Sets.newHashSet(originAclIdList);
            Set<Long> aclIdSet = Sets.newHashSet(acls);
            originAclIdSet.removeAll(aclIdSet);
            if (CollectionUtils.isEmpty(originAclIdSet)) {
                return JSONResult.ok("为角色授权权限成功");
            }
        }
        updateRoleAcls(roleDO.getId(), roleAclDOS, redisUser, roleDO.getGroupId(), acls);
        return JSONResult.ok("为角色授权权限成功");
    }

    @Override
    public JSONResult roleHaveAclTree(LoginAuthReq loginAuthReq, RedisUser redisUser) {
        RoleDO roleDO = roleMapper.uuid(loginAuthReq.getSysRoleUuid());
        if (null == roleDO) {
            return JSONResult.errorMap("待授权的角色不存在");
        }
        loginAuthReq.setRoleId(roleDO.getId());
        if (redisUser.getGroupId().equals(1L)) {
            List<AclModuleLevelDto> list = adminAuthorityService.roleTree(loginAuthReq, redisUser);
            return JSONResult.ok(list);
        } else {
            List<AclModuleLevelDto> list = commonAuthorityService.roleTree(loginAuthReq, redisUser);
            return JSONResult.ok(list);
        }

    }

    @Override
    public JSONResult vipRoleHaveAclTree(UserGroupReq userGroupReq, RedisUser redisUser) {
        UserGroupDO userGroupExists = vipMapper.uuid(userGroupReq.getUserGroupUuid());
        if (null == userGroupExists) {
            return JSONResult.errorMap("带查询的企业/VIP不存在");
        }
        //角色的类型，0：管理员角色，1：普通用户 2其他
        RoleDO roleDO = roleMapper.getVipAdminRole(userGroupExists.getId(), "0");
        if (null == roleDO) {
            return JSONResult.errorMap("未查询到管理员角色或该企业未设置管理员角色");
        }
        LoginAuthReq loginAuthReq = new LoginAuthReq();
        loginAuthReq.setRoleId(roleDO.getId());
        List<AclModuleLevelDto> list = adminAuthorityService.roleTree(loginAuthReq, redisUser);
        return JSONResult.ok(list);
    }

    @Transactional
    public void updateRoleAcls(Long roleId, List<RoleAclDO> aclIdList, RedisUser redisUser, Long groupId, List<Long> acls) {
        roleMapper.deleteRoleAclsByRoleId(roleId);

        if (CollectionUtils.isEmpty(aclIdList)) {
            redisUtil.del(RedisKeyEnum.REDIS_ROLE_ACLS_MAP.getKey() + roleId);
            return;
        }
        List<RoleAclDO> roleUserList = Lists.newArrayList();
        for (RoleAclDO aclId : aclIdList) {
            RoleAclDO roleUserDO = new RoleAclDO();
            roleUserDO.setDelFlag("0");
            roleUserDO.setGroupId(groupId);
            roleUserDO.setSysAclId(aclId.getSysAclId());
            roleUserDO.setSysRoleId(roleId);
            roleUserDO.setSysAclPermissionType(aclId.getSysAclPermissionType());
            roleUserDO.setSysRoleAclUuid(StrUtil.genUUID());
            roleUserDO.setCreateBy(redisUser.getSysUserName());
            roleUserDO.setUpdateBy(redisUser.getSysUserName());
            roleUserDO.setUpdateTime(DateUtil.getDateTime());
            roleUserDO.setCreateTime(DateUtil.getDateTime());
            roleUserList.add(roleUserDO);
        }
        roleMapper.batchInsertRoleAcls(roleUserList);
        aclAsync.roleAclsToRedis(roleId, aclIdList);
    }

    @Transactional
    public void updateUserRoles(Long userId, List<Long> roleIdList, RedisUser redisUser, Long groupId) {
        roleMapper.deleteUserRolesByUserId(userId);

        if (CollectionUtils.isEmpty(roleIdList)) {
            redisUtil.del(RedisKeyEnum.REDIS_USER_ROLES_STR.getKey() + userId);
            return;
        }
        List<RoleUserDO> roleUserList = Lists.newArrayList();
        for (Long aclId : roleIdList) {
            RoleUserDO roleUserDO = new RoleUserDO();
            roleUserDO.setDelFlag("0");
            roleUserDO.setRoleId(aclId);
            roleUserDO.setGroupId(groupId);
            roleUserDO.setSysRoleUserUuid(StrUtil.genUUID());
            roleUserDO.setUserId(userId);
            roleUserDO.setCreateBy(redisUser.getSysUserName());
            roleUserDO.setUpdateBy(redisUser.getSysUserName());
            roleUserDO.setUpdateTime(DateUtil.getDateTime());
            roleUserDO.setCreateTime(DateUtil.getDateTime());
            roleUserList.add(roleUserDO);
        }
        roleMapper.batchInsertUserRoles(roleUserList);
        aclAsync.userRolesToRedis(userId, roleIdList);
    }

    @Override
    public JSONResult vipAdminRoleToAcls(BatchRoleUserReq batchRoleUserReq, RedisUser redisUser) {
        UserGroupDO userGroupExists = vipMapper.uuid(batchRoleUserReq.getUserGroupUuid());
        if (null == userGroupExists) {
            return JSONResult.errorMap("带查询的企业/VIP不存在");
        }
        //角色的类型，0：管理员角色，1：普通用户 2其他
        RoleDO roleDO = roleMapper.getVipAdminRole(userGroupExists.getId(), "0");
        if (null == roleDO) {
            return JSONResult.errorMap("未查询到管理员角色或该企业未设置管理员角色");
        }
        List<RoleAclDO> roleAclDOS = batchRoleUserReq.getAcls();
        List<Long> acls = Lists.newArrayList();
        if (!CollectionUtils.isEmpty(roleAclDOS)) {
            roleAclDOS.forEach(roleAclDO -> {
                acls.add(roleAclDO.getSysAclId());
            });
        }
        List<Long> originAclIdList = authorityMapper.aclsByRoleId(Arrays.asList(roleDO.getId()), null);
        if (originAclIdList.size() == acls.size()) {
            Set<Long> originAclIdSet = Sets.newHashSet(originAclIdList);
            Set<Long> aclIdSet = Sets.newHashSet(acls);
            originAclIdSet.removeAll(aclIdSet);
            if (CollectionUtils.isEmpty(originAclIdSet)) {
                return JSONResult.ok("为角色授权权限成功");
            }
        }
        updateRoleAcls(roleDO.getId(), roleAclDOS, redisUser, roleDO.getGroupId(), acls);
        return JSONResult.ok("授权权限成功");
    }

    @Override
    public JSONResult userHasRoles(BatchRoleUserReq batchRoleUserReq, RedisUser redisUser) {
        UserDO userDO = sysUserMapper.uuid(batchRoleUserReq.getUserUuid());
        if (null == userDO) {
            return JSONResult.errorMap("待授权的用户不存在");
        }
        List<Long> longs = authorityMapper.rolesByUserId(userDO.getId());
        Set<Long> userAclIdSet = longs.stream().map(roleId -> roleId).collect(Collectors.toSet());
        List<RoleDO> list = roleMapper.getAllByGroupId(userDO.getGroupId());
        List<AllRolesRes> allRolesRes = Lists.newArrayList();
        list.forEach(roleDO -> {
            AllRolesRes rolesRes = AllRolesRes.roleDoTOAllRolesRes(roleDO);
            if (userAclIdSet.contains(roleDO.getId())) {
                rolesRes.setChecked(true);
            }
            allRolesRes.add(rolesRes);
        });
        return JSONResult.ok(allRolesRes);
    }

    //校验第三方管理员只允许有一个
    private boolean checkAdminVipOne(RoleDO roleDO) {
        return roleMapper.checkAdminVipOne(roleDO.getGroupId(), roleDO.getId(), roleDO.getSysRoleType()) > 0 ? true : false;
    }
}
